home *** CD-ROM | disk | FTP | other *** search
- // mfc_mdiView.cpp : implementation of the CMfc_mdiView class
- //
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // DataViews Multiple Document Inteface (MDI) example program.
- //
- // CMfc_mdiView class
- // ------------------
- //
- // The simplest way to imagine integrating DataViews into the MFC Document-
- // View architecture is to first think of the DataViews view file as really
- // belonging the CDocument (and with that, an unfortunate clash of nomencla-
- // ture!), and the DataView's screen and drawport as belonging more naturally
- // with the MFC CView.
- //
- // The CMfc_mdiView class then is responsible for creating the DataViews
- // screen and drawport used to display the view, updating dynamics (indirect-
- // ly through a TimerProc), and repairing the screen when it is resized, or
- // or partially obscured, or deiconified.
- //
- // The InitDv() method gets called by the CDocument and gets passed in the
- // view that was loaded. It creates a DataViews screen object by calling
- // TscOpenSet() and passing in the window handle (from GetSafeHwnd). Doing
- // this tells the TscOpenSet() routine to create a DataViews screen object
- // using the window handle supplied rather than creating its own. In DataViews
- // parlance, this is called "creating a screen with an externally created
- // window."
- //
- // Once the screen object is created, the rest of the code is basic DataViews
- // boilerplate code: the drawport is created, the view's data sources are
- // opened and and the first iteration of data read, the drawport is drawn
- // initially, and then SetTimer() is called to set up a timerproc which will
- // be used to continously update the view's dynamic objects.
- //
- // In addition, there are message handlers for handling specific user interaction,
- // namely WM_MOUSEMOVE, WM_LBUTTONDOWN and WM_LBUTTONDBLCLK messages. The
- // table below shows how you can see the results of these interactions:
- //
- // Message View Name Interaction Seen by:
- // ----------------------------------------------------------------------------
- // WM_MOUSEMOVE view3.v moving the mouse over the slider
- // WM_LBUTTONDOWN view1.v clicking on the toggle input object
- // WM_LBUTTONDBLCLK <all views> double click on any DataViews object
- //
- //
- // In addition to these, there are message handlers for the WM_ACTIVATE,
- // WM_PALETTECHANGED, and WM_QUERYNEWPALETTE messages for handling color palette
- // changes.
-
- // When the user closes the view, the OnDestroy() messages kills the timer,
- // and the CMfc_mdiView's destructor destroys the drawport and closes (de-
- // stroys the screen).
- //
- // The OnDraw() method redraws the screen any time the screen needs to be
- // all or partially redrawn.
- //
- /////////////////////////////////////////////////////////////////////////////
-
-
- #include "stdafx.h"
- #include "mfc_mdi.h"
- #include "mfc_mdiDoc.h"
- #include "mfc_mdiView.h"
-
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // UpdateDynamicsTimerProc()
- //
- // TimerProc callback function. This routine gets called whenever the time
- // interval has expired (see SetTimer). It casts the nIDEvent parameter to
- // be a pointer to a CMfc_mdiView object (effectively the 'this' pointer in
- // this module-- see the InstallTimer() method below) and uses that to call
- // the DataViews routines TviReadData() to get the next iteration of data
- // and TdpDrawNext() to update the screen.
- //
- void CALLBACK EXPORT UpdateDynamicsTimerProc(
- HWND hWnd, //handle of CWnd that called SetTimer
- UINT nMsg, //WM_TIMER
- UINT nIDEvent, //timer identification
- DWORD dwTime //system time
- )
- {
- CMfc_mdiView* pView = (CMfc_mdiView*)nIDEvent;
-
- TviReadData(pView->GetDocument()->GetDVview());
- TdpDrawNext(pView->GetDrawport());
- }
-
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CMfc_mdiView
-
- IMPLEMENT_DYNCREATE(CMfc_mdiView, CView)
-
- BEGIN_MESSAGE_MAP(CMfc_mdiView, CView)
- //{{AFX_MSG_MAP(CMfc_mdiView)
- ON_WM_SIZE()
- ON_WM_DESTROY()
- ON_WM_MOUSEMOVE()
- ON_WM_LBUTTONDOWN()
- ON_WM_LBUTTONDBLCLK()
- ON_WM_ACTIVATE()
- ON_WM_PALETTECHANGED()
- ON_WM_QUERYNEWPALETTE()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CMfc_mdiView construction/destruction
-
-
- /////////////////////////////////////////////////////////////////////////////
- //
- CMfc_mdiView::CMfc_mdiView()
- : m_Scr(0), m_Dp(0), m_TimerID(0), m_Loc(0), m_DvProc(0)
- {
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // OnSize()
- //
- // If we have a screen object (m_Scr), call TscReset(), which resizes the
- // screen and any of its drawports. Note that no drawing is done at this
- // time; this is because the WM_SIZE message causes a WM_PAINT message
- // which the framework handles by calling the OnDraw() method.
- //
- void CMfc_mdiView::OnSize(UINT nType, int cx, int cy)
- {
- CView::OnSize(nType, cx, cy);
- if(m_Scr)
- TscReset(m_Scr);
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // OnDraw()
- //
- // The OnDraw() method, after checking that we have both a screen and a
- // drawport, set the screen object for this view (m_Scr) to be the current
- // screen, and then checks to see if the drawport has been previously drawn.
- // If it has not, then simply draw all of it. More interesting is if it has,
- // in which case we get the current window message and pass that along with
- // a pointer to a DataViews WINEVENT structure to the low-level graphics
- // routine GRwe_convert(). This routine populates the WINEVENT structure
- // with, among other things, the area (or region) of the drawport that needs
- // to be updated. Now we can more efficiently redraw just that portion of
- // the screen that needs to be redrawn.
- //
- void CMfc_mdiView::OnDraw(CDC* pDC)
- {
- if(m_Scr && m_Dp)
- {
- TscSetCurrentScreen(m_Scr);
- if(TdpIsDrawn(m_Dp))
- {
- WINEVENT we;
- GRwe_convert((ADDRESS)GetCurrentMessage(), &we);
- TdpRedraw(m_Dp, &we.region, YES);
- }
- else
- TdpDraw(m_Dp);
-
- TscFlush(m_Scr);
- }
- }
-
-
-
- /////////////////////////////////////////////////////////////////////////////
- // CMfc_mdiView diagnostics
-
- #ifdef _DEBUG
- void CMfc_mdiView::AssertValid() const
- {
- CView::AssertValid();
- }
-
- void CMfc_mdiView::Dump(CDumpContext& dc) const
- {
- CView::Dump(dc);
- }
-
- CMfc_mdiDoc* CMfc_mdiView::GetDocument() // non-debug version is inline
- {
- ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMfc_mdiDoc)));
- return (CMfc_mdiDoc*)m_pDocument;
- }
- #endif //_DEBUG
-
- /////////////////////////////////////////////////////////////////////////////
- // CMfc_mdiView message handlers
-
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // InstallTimer():
- //
- // Checks for a previously installed timer, and if so, kills it first.
- // We then install a new timer, passing the 'this' pointer through the
- // nIDEvent (timer identification) field. The 'this' pointer is then cast
- // to a CMfc_mdiView* in the callback UpdateDynamicsTimerProc() which
- // then updates the DataViews view's dynamics.
- //
- void CMfc_mdiView::InstallTimer(UINT nTimeInterval)
- {
- if(m_TimerID)
- KillTimer(m_TimerID);
- m_TimerID = SetTimer((UINT)this, nTimeInterval,UpdateDynamicsTimerProc);
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- //
- void CMfc_mdiView::DisplayObjectType(OBJECT Ob)
- {
- char* obType = 0;
-
- switch(VOobType(Ob))
- {
- case OT_ARC : obType = "Arc" ; break;
- case OT_CIRCLE : obType = "Circle" ; break;
- case OT_DG : obType = "Graph" ; break;
- case OT_ELLIPSE : obType = "Ellipse" ; break;
- case OT_ICON : obType = "Icon" ; break;
- case OT_IMAGE : obType = "Image" ; break;
- case OT_INPUT : obType = "Input Object" ; break;
- case OT_LINE : obType = "Line" ; break;
- case OT_POLYGON : obType = "Polygon" ; break;
- case OT_RECTANGLE : obType = "Rectangle" ; break;
- case OT_SUBDRAWING : obType = "Subdrawing" ; break;
- case OT_TEXT : obType = "Hardware text" ; break;
- case OT_VTEXT : obType = "Vector text" ; break;
- case OT_SFTEXT : obType = "Scalable font" ; break;
- default : obType = "Unknown" ; break;
- }
-
- CString msg;
- msg.Format("Selected object type is: %s", obType);
- AfxMessageBox((LPCTSTR)msg);
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- //
- BOOL CMfc_mdiView::SetupLoc(const MSG* msg)
- {
- if(m_Scr && m_Dp)
- {
- WINEVENT we;
- TscSetCurrentScreen(m_Scr);
- GRwe_convert((ADDRESS)msg, &we);
- return (BOOL)TloWinEventSetup(m_Loc,&we,m_Scr,m_Dp);
- }
- return FALSE;
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // InitDV()
- //
- //
- BOOL CMfc_mdiView::InitDv(VIEW dvView)
- {
- RECTANGLE WholeWorld = { -16383, -16383, 16383, 16383};
-
- // Open the DataViews screen object...
- m_Scr = TscOpenSet("W", (char*)0,
- V_WIN32_WINDOW_HANDLE, GetSafeHwnd(),
- V_WIN32_DOUBLE_BUFFER,TRUE,
- V_ACTIVE_CURSOR, V_END_OF_LIST);
-
- // ...check for any errors, such as licensing problems...
- if(TscOpenError())
- {
- m_Scr = 0;
- return FALSE;
- }
-
- // ..get the DataViews driver default WinProc. We'll use this later
- // to handle special case messages...
- GRget(V_WIN32_WINDOWPROC, &m_DvProc, V_END_OF_LIST);
-
- // ..create our location object for handling user input...
- m_Loc = VOloCreate();
-
- // ..create the drawport...
- m_Dp = TdpCreateStretch(m_Scr,dvView,0,&WholeWorld);
-
- /////////////////////////////////////////////////////////////////////////
- //
- // ...or use this form to avoid distortion (see DV-Tools User's Guide
- // for discussion on drawport creation):
- //
- // m_Dp = TdpCreate(m_Scr,dvView,0,&WholeWorld);
- //
- /////////////////////////////////////////////////////////////////////////
-
-
- // ...draw the drawport. A technical aside: we really do not have make
- // this call to TdpDraw(), as this would more naturally happen in the
- // OnDraw() method. However, in this particular example program, the
- // effect we are aiming for is for the dynamic objects to appear instant-
- // ly dynamic from the very start. Since TdpDraw() must be called prior
- // to calling TdpDrawNext() (the routine that actually updates dynamics),
- // we need to call it now rather than later.
- TdpDraw(m_Dp);
-
- // Now we are ready to open the view's data sources, read the first
- // iteration of data and update the the drawport by calling TdpDrawNext()...
- TviOpenData(dvView);
- TviReadData(dvView);
- TdpDrawNext(m_Dp);
-
- // ...and finally, start the timer process that will continuously update
- // the view's dynamics.
- InstallTimer();
-
- return TRUE;
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // Clean up DataViews data structures owned by the CView, namely the screen
- // and drawport. The important thing here is that TscClose() needs to be
- // called *before* the Window's window (m_hWnd) goes out of existence,
- // otherwise, without a valid window handle, DataViews will not be able to
- // properly clean up system resources it has allocated.
- //
- // To that end, cleanup is done while processing the WM_DESTROY message
- // (and before the base class OnDestroy() method), and not, as one might
- // think at first glance, in the destructor, as it is too late by then.
- //
- void CMfc_mdiView::OnDestroy()
- {
- if(m_Dp)
- TdpDestroy(m_Dp);
-
- if(m_Scr)
- TscClose(m_Scr);
-
- if(m_Loc)
- VOobDereference(m_Loc);
-
- CView::OnDestroy();
-
- if(m_TimerID)
- KillTimer(m_TimerID);
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // Handling User Input
- //
- // Handling user input in this example means handling the mouse messages for
- // motion (WM_MOUSEMOVE), left button down (WM_LBUTTONDOWN), and left button
- // double clicks (ON_WM_LBUTTONDBLCLK).
- //
-
-
- void CMfc_mdiView::OnMouseMove(UINT nFlags, CPoint point)
- {
- if(SetupLoc(GetCurrentMessage()))
- VUerHandleLocEvent(m_Loc);
- }
-
- void CMfc_mdiView::OnLButtonDown(UINT nFlags, CPoint point)
- {
- if(SetupLoc(GetCurrentMessage()))
- VUerHandleLocEvent(m_Loc);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // Double click Messages
- //
- // DataViews does not support doubleclick messages, but this method shows
- // how to take a double click message and convert it to a DataViews location
- // object that can be used to pop up a message box with the object's name...
- //
- void CMfc_mdiView::OnLButtonDblClk(UINT nFlags, CPoint point)
- {
- MSG fakeMsg; // used to fool DataViews...
- const MSG* realMsg = GetCurrentMessage();
-
- // Change the message type to be a left button down message
- fakeMsg = *realMsg;
- fakeMsg.message = WM_LBUTTONDOWN;
-
- SetupLoc((const MSG*)&fakeMsg);
- OBJECT selectedOb = TloGetSelectedObject(m_Loc);
- if(selectedOb)
- DisplayObjectType(selectedOb);
- }
-
-
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // Special Case Messages
- //
- // The following three message handlers handle the WM_ACTIVATE,
- // WM_PALETTECHANGED, and WM_QUERYNEWPALETTE messages respectively. These
- // messages need to be special cased in order for the DataViews Windows
- // driver to properly handle color palette changes. This is done by
- // simply calling the driver's own WinProc (passing in the particular window
- // handle) and the message parameters.
-
- void CMfc_mdiView::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
- {
- CView::OnActivate(nState, pWndOther, bMinimized);
-
- // If our application has been activated, we want to tell the DataViews
- // driver to select our colormap into the system palette...
- const MSG* msg = GetCurrentMessage();
- ::CallWindowProc((WNDPROC)m_DvProc,m_hWnd,msg->message,msg->wParam,msg->lParam);
- }
-
- void CMfc_mdiView::OnPaletteChanged(CWnd* pFocusWnd)
- {
- CView::OnPaletteChanged(pFocusWnd);
-
- // In this case, some other application has changed the palette, so we need
- // to tell the driver to re-select ours...
- const MSG* msg = GetCurrentMessage();
- ::CallWindowProc((WNDPROC)m_DvProc,m_hWnd,msg->message,msg->wParam,msg->lParam);
- }
-
- BOOL CMfc_mdiView::OnQueryNewPalette()
- {
- // This is basically the same situation as with OnPaletteChanged() above...
- const MSG* msg = GetCurrentMessage();
- ::CallWindowProc((WNDPROC)m_DvProc,m_hWnd,msg->message,msg->wParam,msg->lParam);
-
- return CView::OnQueryNewPalette();
- }
-
-